package cn.ac.cintcm.prespring.cluster.set;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.ac.cintcm.prespring.cluster.base.Similarity;

public abstract class BaseSimFj{
	private float simRate;
	protected String textFromUrl;
	protected String textToUrl;

	public BaseSimFj(float simRate){
		Similarity.simRate=simRate;
		this.simRate=simRate;
	}

	public String getTextFromUrl() {
		return textFromUrl;
	}

	public void setTextFromUrl(String textFromUrl) {
		this.textFromUrl = textFromUrl;
	}

	public String getTextToUrl() {
		return textToUrl;
	}

	public void setTextToUrl(String textToUrl) {
		this.textToUrl = textToUrl;
	}
	
	public Map<String,List<Integer>> readFromText() throws Exception{
		BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(textFromUrl),"UTF8"));
		String line="";
		Map<String,List<Integer>> map=new HashMap<String,List<Integer>>();
		while((line=reader.readLine())!=null){
			System.out.println(line);
			String[] s=line.split(":");
			if(s.length==2){
				String fjId=s[0];				
				String[] ss=s[1].split(",");
				List<Integer> idSet=new ArrayList<Integer>();
				for(int i=0;i<ss.length;i++){
					Integer id=new Integer(ss[i]);
					idSet.add(i,id);
				}
				map.put(fjId,idSet);
			}
		}
		reader.close();
		return map;
	}
	
	/**
	 * @return similar pairs with similarity sequentially form high to low
	 */
	public Map<String,List<Similar>> calcSimilarity(Map<String,List<Integer>> map) throws Exception{
		Map<String,List<Similar>> returnMap=new HashMap<String,List<Similar>>();
		Set<String> keys=map.keySet();
		Iterator<String> iter=keys.iterator();
		int count=0;
		while(iter.hasNext()){						
			String key=iter.next();
			if((++count)%50==0){
				System.out.println(" map size now is " + map.size()+" fjid is "+key);
			}
			List<Integer> value=map.get(key) ;
			while(iter.hasNext()){
				String k=iter.next().toString();
				List<Integer> compValue = map.get(k);
				float rate=Similarity.simRate(value,compValue);
				if(rate>=simRate){
					if (returnMap.get(key) == null) {
						List<Similar> result = new ArrayList<Similar>();
						Similar sim=new Similar(k,rate);
						result.add(sim);
						returnMap.put(key, result);
					} else {
						Similar sim=new Similar(k,rate);
						List<Similar> sims=returnMap.get(key);
						int i=0;
						//insert sort
						for(i=0;i<sims.size();i++){
							if(sims.get(i).getSimRate()<rate){
								sims.add(i,sim);
								break;
							}
						}
						if(i==sims.size()){
							sims.add(sim);
						}
						//returnMap.put(key,sims);
					}
					if (returnMap.get(k) == null) {
						List<Similar> result = new ArrayList<Similar>();
						Similar sim=new Similar(key,rate);
						result.add(sim);
						returnMap.put(k, result);
					} else {
						Similar sim=new Similar(key,rate);
						List<Similar> sims=returnMap.get(k);
						int i=0;
						//insert sort
						for(i=0;i<sims.size();i++){
							if(sims.get(i).getSimRate()<=rate){
								sims.add(i,sim);
								break;
							}
						}
						if(i==sims.size()){
							sims.add(sim);
						}
//						returnMap.put(key,sims);
					}
				}
			}
			map.remove(key);
			iter=map.keySet().iterator();
		}
		map.clear();
		map=null;
		return returnMap;
	}
	
	/**
	 * write similar pairs to text: one's similars are ordered sequentially according to their similarity to itself.
	 */
	public void writeSimilarityToText(Map<String,List<Similar>> map) throws Exception{
		BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(textToUrl,false),"UTF8"));
		StringBuilder sb = new StringBuilder();
		Set<String> keys=map.keySet();
		Iterator iter=keys.iterator();
		while(iter.hasNext()){
			String fjId=iter.next().toString();
			sb.append(fjId+":");
			List<Similar> similars=map.get(fjId);
//			sortSimilars(similars);
			for(int i=0;i<similars.size();i++){
				Similar sim=similars.get(i);
				sb.append(sim.getTarget()+","+sim.getSimRate()+";");
			}
//			Iterator iter2=simFjIds.iterator();
//			while(iter2.hasNext()){
//				String simFjId=iter2.next().toString();
//				sb.append(simFjId+",");
//			}
			if (sb.length() > 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
			System.out.println(sb.toString());
			writer.append(sb.toString());
			writer.write("\r\n");
			sb.setLength(0);
		}
		writer.close();
		map.clear();
		map=null;
	}
	
	/**
	 * sort similars according to their simRate from high to low
	 * @param sims
	 */
	private void sortSimilars(List<Similar> similars){
		if(similars==null ||similars.size()<=1){
			return;
		}
		//bubble sort
		for(int i=0;i<similars.size();i++){
			for(int j=1;j<similars.size()-i;j++){
				if(similars.get(i).getSimRate()<similars.get(j).getSimRate()){
					Similar temp=similars.get(i);
					similars.set(i,similars.get(j));
					similars.set(j,temp);
				}
			}
		}
	}
	/**
	 * @return similar pairs without similarity
	 */
	public Map<String,List<String>> calcSim() throws Exception{
		Map<String,List<Integer>> map=readFromText();
		Map<String,List<String>> returnMap=new HashMap<String,List<String>>();
		Set<String> keys=map.keySet();
		Iterator<String> iter=keys.iterator();
		int count=0;
		while(iter.hasNext()){						
			String key=iter.next();
			if((++count)%50==0){
				System.out.println("now map size is " + map.size()+" fjid is "+key);
			}
			List<Integer> value=map.get(key) ;
			while(iter.hasNext()){
				String k=iter.next().toString();
				List<Integer> compValue = map.get(k);
				boolean isSim=Similarity.isSim(value,compValue);
				if(isSim){
					if (returnMap.get(key) == null) {
						List<String> result = new ArrayList<String>();
						result.add(k);
						returnMap.put(key, result);
					} else {
						returnMap.get(key).add(k);
					}
					if (returnMap.get(k) == null) {
						List<String> result = new ArrayList<String>();
						result.add(key);
						returnMap.put(k, result);
					} else {
						returnMap.get(k).add(key);
					}
				}
			}
			map.remove(key);
			iter=map.keySet().iterator();
		}
		map.clear();
		map=null;
		return returnMap;
	}
	
	/**
	 * write similar pairs to text with no sequence
	 */
	public void writeSimToText(Map<String,List<String>> map) throws Exception{
		BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(new FileOutputStream(textToUrl,true),"UTF8"));
		StringBuilder sb = new StringBuilder();
		Set<String> keys=map.keySet();
		Iterator iter=keys.iterator();
		while(iter.hasNext()){
			String fjId=iter.next().toString();
			sb.append(fjId+":");
			List<String> simFjIds=map.get(fjId);
			Iterator iter2=simFjIds.iterator();
			while(iter2.hasNext()){
				String simFjId=iter2.next().toString();
				sb.append(simFjId+",");
			}
			if (sb.length() > 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
			System.out.println(sb.toString());
			writer.append(sb.toString());
			writer.write("\r\n");
			sb.setLength(0);
		}
		writer.close();
		map.clear();
		map=null;
	}

	public float getSimRate() {
		return simRate;
	}

	public void setSimRate(float simRate) {
		this.simRate = simRate;
	}
}
